package com.szeldon.declatest.exec.plugins.jms;

import java.util.Properties;
import java.util.logging.Logger;

import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.jmx.BrokerView;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.xml.XmlTest;

import com.szeldon.declatest.declaration.TestsSuiteDeclaration;
import com.szeldon.declatest.declaration.endpoints.EndpointDeclaration;
import com.szeldon.declatest.declaration.scenario.ScenarioDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.DoScenarioStepPartDeclaration;
import com.szeldon.declatest.declaration.settings.JmsSettingsPartDeclaration;
import com.szeldon.declatest.declaration.steps.ScenarioStepDeclaration;
import com.szeldon.declatest.exec.ExecListenerTester;
import com.szeldon.declatest.exec.TestSuiteExecHistory;
import com.szeldon.declatest.exec.events.dostep.jms.JmsMessageReceivedExecEvent;
import com.szeldon.declatest.exec.events.dostep.jms.JmsMessageSentExecEvent;
import com.szeldon.declatest.exec.plugins.JMSDoScenarioPartExecutorPlugin;
import com.szeldon.utils.FileUtils;

/**
 * Unit tests for the {@link JMSDoScenarioPartExecutorPlugin} executor plugin. These tests are using just the plugin (no
 * reading from test suite files, no executors etc.).
 * 
 * @author szeldon
 * 
 */
public class JMSDoScenarioPartExecutorPluginTest {

    private static final String REQUEST_PATH_BASIS = "tests-res/com/szeldon/declatest/exec/plugins/jms/";
    private static final String QUEUE_NAME_PREFIX = "dynamicQueues/";
    private static final String TOPIC_NAME_PREFIX = "dynamicTopics/";

    private static Logger logger = Logger.getLogger(JMSDoScenarioPartExecutorPluginTest.class.getName());

    // useful TestNG properties
    private XmlTest xmlTest;

    // JMS properties
    private BrokerView adminView;

    @BeforeClass
    public void beforeClass(ITestContext testContext) throws Exception {
        xmlTest = testContext.getCurrentXmlTest();

        // gets JMS server properties
        BrokerService brokerService = (BrokerService) testContext
                .getAttribute(JmsTestsConfigurator.CONTEXT_ATTRIBUTE_NAME_FOR_JMS_SERVER);
        adminView = brokerService.getAdminView();
    }

    @Test
    public void firstBasicSendReceiveJmsRequestTest(ITestContext testContext) throws Exception {
        String notQualifiedSendDestinationName = "firstBasicSendReceiveJmsRequestTest-send";
        String requestPath = REQUEST_PATH_BASIS + "jms-request-01.xml";
        String notQualifiedReceiveDestinationName = "firstBasicSendReceiveJmsRequestTest-receive";
        executeSimpleSendReceiveTest("sendEndpointId", "sendSettingsId", notQualifiedSendDestinationName, "sendStepId",
                "send step description", "send endpoint description", requestPath,
                FileUtils.readFileContent(requestPath), QUEUE_NAME_PREFIX + notQualifiedSendDestinationName, "receiveEndpointId",
                "receiveSettingsId", notQualifiedReceiveDestinationName, "receiveStepId", "receive step description",
                "receive endpoint description", REQUEST_PATH_BASIS + "jms-response-01.xml",
                FileUtils.readFileContent(REQUEST_PATH_BASIS + "jms-response-01.xml"), QUEUE_NAME_PREFIX
                        + notQualifiedReceiveDestinationName, "scenarioId", "queue");
    }

    public void secondBasicSendReceiveJmsRequestTest(ITestContext testContext) throws Exception {
        String notQualifiedSendDestinationName = "secondBasicSendReceiveJmsRequestTest-send";
        String requestPath = REQUEST_PATH_BASIS + "jms-request-01.xml";
        String notQualifiedReceiveDestinationName = "secondBasicSendReceiveJmsRequestTest-receive";
        executeSimpleSendReceiveTest("sendEndpointId", "sendSettingsId", notQualifiedSendDestinationName, "sendStepId",
                "send step description", "send endpoint description", requestPath,
                FileUtils.readFileContent(requestPath), TOPIC_NAME_PREFIX + notQualifiedSendDestinationName,
                "receiveEndpointId", "receiveSettingsId", notQualifiedReceiveDestinationName, "receiveStepId",
                "receive step description", "receive endpoint description", REQUEST_PATH_BASIS + "jms-response-01.xml",
                FileUtils.readFileContent(REQUEST_PATH_BASIS + "jms-response-01.xml"), TOPIC_NAME_PREFIX
                        + notQualifiedReceiveDestinationName, "scenarioId", "topic");
    }

    /**
     * 
     * @param sendEndpointId
     * @param sendSettingsId
     * @param notQualifiedSendDestinationName
     * @param sendStepId
     * @param sendStepDescription
     * @param sendEndpointDescription
     * @param requestPath
     * @param requestContent
     * @param qualifiedSendDestinationName
     * @param receiveEndpointId
     * @param receiveSettingsId
     * @param notQualifiedReceiveDestinationName
     * @param receiveStepId
     * @param receiveStepDescription
     * @param receiveEndpointDescription
     * @param responsePath
     * @param responseContent
     * @param qualifiedReceiveDestinationName
     * @param scenarioId
     * @param destinationType
     * @throws Exception
     */
    private void executeSimpleSendReceiveTest(String sendEndpointId, String sendSettingsId,
            String notQualifiedSendDestinationName, String sendStepId, String sendStepDescription,
            String sendEndpointDescription, String requestPath, String requestContent,
            String qualifiedSendDestinationName, String receiveEndpointId, String receiveSettingsId,
            String notQualifiedReceiveDestinationName, String receiveStepId, String receiveStepDescription,
            String receiveEndpointDescription, String responsePath, String responseContent,
            String qualifiedReceiveDestinationName, String scenarioId, String destinationType) throws Exception {

        String serverUrl = xmlTest.getParameter(JmsTestsConfigurator.JMS_BIND_ADDRESS_PARAMETER);

        // objects for sending
        DoScenarioStepPartDeclaration sendDoScenarioStepPart = new DoScenarioStepPartDeclaration(sendStepId);
        ScenarioStepDeclaration sendStep = new ScenarioStepDeclaration(sendStepId, sendStepDescription, sendEndpointId,
                requestPath);
        Properties sendProperties = new Properties();
        EndpointDeclaration sendEndpoint = new EndpointDeclaration(sendEndpointId, sendEndpointDescription, serverUrl,
                sendSettingsId);
        JmsSettingsPartDeclaration sendSettings = new JmsSettingsPartDeclaration(sendSettingsId,
                "settings description", "sendUser", "sendPassword", destinationType, qualifiedSendDestinationName,
                "send", "60000");

        // objects for receiving
        JmsSettingsPartDeclaration receiveSettings = new JmsSettingsPartDeclaration(receiveSettingsId,
                "receive settings description", "receiveUser", "receivePassword", destinationType,
                qualifiedReceiveDestinationName, "receive", "60000");
        DoScenarioStepPartDeclaration receiveDoScenarioStepPart = new DoScenarioStepPartDeclaration(receiveStepId);
        ScenarioStepDeclaration receiveStep = new ScenarioStepDeclaration(receiveStepId, receiveStepDescription,
                receiveEndpointId, responsePath);
        Properties receiveProperties = new Properties();
        EndpointDeclaration receiveEndpoint = new EndpointDeclaration(receiveEndpointId, receiveEndpointDescription,
                serverUrl, receiveSettingsId);

        // general objects
        TestsSuiteDeclaration suite = new TestsSuiteDeclaration();
        ScenarioDeclaration scenario = new ScenarioDeclaration(scenarioId, "scenario description");
        TestSuiteExecHistory history = new TestSuiteExecHistory("testSuiteId");
        ExecListenerTester eventListener = new ExecListenerTester();
        eventListener.addEventToCompare(new JmsMessageSentExecEvent(scenarioId, null, null, sendStepId,
                sendStepDescription, sendEndpointId, requestPath, sendEndpointDescription, serverUrl, sendSettingsId,
                destinationType, qualifiedSendDestinationName, requestContent));
        eventListener.addEventToCompare(new JmsMessageReceivedExecEvent(scenarioId, null, null, receiveStepId,
                receiveStepDescription, receiveEndpointId, responsePath, receiveEndpointDescription, serverUrl,
                receiveSettingsId, destinationType, qualifiedReceiveDestinationName, responseContent));

        // adds listener for queue... will respond to messages send by first executor
        TestMessageListener messageListener = new TestMessageListener(serverUrl, qualifiedReceiveDestinationName,
                requestContent, responseContent);
        messageListener.start(notQualifiedSendDestinationName, serverUrl);

        // creates and executes plugin
        JMSDoScenarioPartExecutorPlugin plugin = new JMSDoScenarioPartExecutorPlugin();
        plugin.execute(sendDoScenarioStepPart, sendStep, suite, sendProperties, sendEndpoint, sendSettings, scenario,
                history, eventListener);

        plugin.execute(receiveDoScenarioStepPart, receiveStep, suite, receiveProperties, receiveEndpoint,
                receiveSettings, scenario, history, eventListener);

        // waits for message listener to end
        while (!messageListener.isTestEnded()) {
            logger.finer("Sleeping because of waiting for JMS communication to end...");
            Thread.sleep(100);
        }

        // checks if request sent is equal to the received one
        Assert.assertEquals(messageListener.isTestPassed(), true, messageListener.getTestResultDescription());

        // checks if proper events were created during execution
        Assert.assertEquals(eventListener.isExecutionOk(), true, eventListener.notOkExecutionDescription());
    }
}
